﻿/*    
Nemulation: A .NET based framework/platform for virtualization applications
Copyright (C) 2011 Bryan Perris

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using NEmu.Utilities;
using System.Security;

namespace NEmu.Memory.MemoryPages
{
    [Serializable]
    [SecurityCritical(SecurityCriticalScope.Everything)]
    public sealed class StructMemoryPage<TStruct> : MemoryPage, ISerializable where TStruct : struct
    {
        IntPtr m_StructPtr;
        private bool _disposed;

        public StructMemoryPage()
        {
            m_StructPtr = StructTools.AllocateUnmanagedStructure<TStruct>();
        }

        private StructMemoryPage(SerializationInfo info, StreamingContext context)
        {
            byte[] buffer = (byte[])info.GetValue("UnmanagedStruct", typeof(byte[]));
            m_StructPtr = StructTools.AllocateUnmanagedStructure<TStruct>();
            Marshal.Copy(buffer, 0, m_StructPtr, buffer.Length);
        }
        
        public override int Read(int address)
        {
            #if DEBUG
                if (address > BoundaryAddress.ToInt32()) return -1;
            #endif

            return (int)Marshal.ReadByte(m_StructPtr, address);
        }

        public override void Write(int address, byte value)
        {
            #if DEBUG
                if (address > BoundaryAddress.ToInt32()) return;
            #endif

            Marshal.WriteByte(m_StructPtr, address, value);
        }

        public override int Size
        {
            get
            {
                return Marshal.SizeOf(typeof(TStruct));
            }
        }

        public override void Clear()
        {
            StructTools.InitUnmanagedStructure<TStruct>(m_StructPtr);
        }

        protected override void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    Marshal.DestroyStructure(m_StructPtr, typeof(TStruct));
                }

                _disposed = true;
            }
        }

        public IntPtr StructPtr
        {
            get { return m_StructPtr; }
        }

        public IntPtr BoundaryAddress
        {
            get { return IntPtr.Add(m_StructPtr, Size); }
        }

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            byte[] buffer = new byte[Size];
            Marshal.Copy(m_StructPtr, buffer, 0, Size);
            info.AddValue("UnmanagedStruct", buffer);
        }

        #endregion
    }
}
